package com.cskaoyan.javase.object._1getclass;

/**
 * getClass方法
 * 1.方法的声明:
 * public final native Class<?> getClass();
 *  注:
 *      a.它是一个public方法,调用它无需注意权限
 *      b.该方法是final修饰的,表示该方法不能被重写,只能继承使用.
 *      c.native修饰,表示它是一个本地方法,它没有方法体
 *      d.Class是方法的返回值类型,表示该方法返回一个Class对象
 *      e.<?>这是Java中的泛型,
 *          泛型可以在程序的编译时期记忆数据类型,同时兼具Object式的灵活性.
 *          是Java中非常非常重要的语法
 *          并且为了JDK版本兼容,Java中的泛型不是真泛型,而是伪泛型(和C++)
 *          Java的泛型仅在编译时期生效,不影响程序执行
 *          所以在这里,我们直接去掉泛型,不用泛型
 *      f.方法不需要任何参数
 *
 * 2.方法的作用:
 *      返回Class对象
 *      什么是Class对象呢?
 * 为了让程序员能够在程序的运行期间动态的了解和获取一个类的类型信息
 * JVM在类加载某个类的同时(在加载的步骤中),会直接在堆上创建一个封装了
 *      该类类型信息的对象,类型信息包括:
 *          a.类名
 *          b.变量
 *          c.方法
 *          d.构造器
 *          ...
 *       这就是Class对象
 *       由于Class对象在程序的运行期间描述该类类型信息
 *       所以Class对象也称之为"类的运行时对象",简称"类对象"
 *
 * 有了Class对象后,程序员就可以在程序的运行期间,动态获取类型信息,从而完成一些操作.
 * 这个操作,实际上就是Java中的反射技术,Class对象是反射的基础,反射就是Class API的调用.
 * 反射获取类的构造器后,就可以使用构造器创建对象,使用反射创建对象,也是创建对象的一种方式(而且是开发中最常用的方式)
 *
 * 3.注意事项:
 *      1,类加载只有一次,那么某个类的Class对象有几个呢?
 *          只有一个,是唯一的
 *      2,Class对象是JVM在类加载某个类的同时在堆上创建的,
 *          不是程序员手动new创建的,更不是getClass方法创建的
 *      3,getClass方法获取Class对象是非常少见的
 *          它的最主要用途在于: 用来判断两个引用所指向的对象,是否是同种类型对象
 *          原因是因为: 一个类的类加载只要一次,某个类的Class对象是唯一的
 *          语法:
 *                 引用.getClass == 引用.getClass
 *          如果返回true说明是同种对象,反之就不是.
 *
 *          双等号判断引用数据类型,必须要求是同种数据类型
 *
 *
 *
 * @since 11:11
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Student s = new Student();
        Student s2 = new Student();
        Class stuClazz = s.getClass();
        Class stuClazz2 = s2.getClass();
        Teacher t = new Teacher();
        Class teacherClazz = t.getClass();

        // 都是Student类的Class对象,是唯一的,"=="判断地址,确实是相同的,返回true
        System.out.println(stuClazz == stuClazz2);
        // 不同类的Class对象肯定不是同一个对象,返回false
        System.out.println(stuClazz == teacherClazz);

        /*
            上述"=="能够判断,是因为都是Class类型
            但是泛型会影响程序编译,
                编译器把泛型不同的同种数据类型,看成两种数据类型,"=="就不能连接了
         */
        Class<? extends Student> c1 = s.getClass();
        Class<? extends Teacher> c2 = t.getClass();
        // System.out.println(c1 == c2);


        System.out.println("-------------------------------");
        System.out.println(judgeDataType(s, s2));
        System.out.println(judgeDataType(s, t));

        /*
            // 获取类的全限定类名
             getName()
            // 获取类名
            getSimpleName()
         */
        System.out.println(teacherClazz.getName());
        System.out.println(teacherClazz.getSimpleName());
    }

    /*
        如果想在一个方法中使用"=="Class对象判断数据类型
        也需要保证"=="两边的数据类型一致,否者双等号不能连接
     */
    public static boolean judgeDataType(Student s1, Student s2) {
        return s1.getClass() == s2.getClass();
    }

    /*public static boolean judgeDataType(Student s1, Teacher t) {
        return s1.getClass() == t.getClass();
    }*/
    // 实际开发中,如果有需求判断引用指向对象的数据类型,建议引用一律用Object
    public static boolean judgeDataType(Object o1, Object o2) {
        return o1.getClass() == o2.getClass();
    }
}

class Teacher {
}

class Student {
}